package com.gomtel.smartdevice.net.okhttp;

import android.content.Context;
import android.util.Log;

import com.xihespace.forestryapp.utils.gson.GsonUtils;

import org.greenrobot.eventbus.EventBus;
import org.json.JSONObject;

import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

@SuppressWarnings("ALL")
public class OkHttpUtils {
    private static String TAG = OkHttpUtils.class.getSimpleName();
    private static final int mSize = 10;
    public static final ExecutorService mThreadPools = Executors.newFixedThreadPool(mSize);
    private static final PriorityQueue<OkHttpParam> mArrayBlockingQueue = new PriorityQueue<>(mSize);
    public static OkHttpClient mOkHttpClient;

    private static OkHttpParam mOkHttpUtilsInnerClass = null;

    /**
     * post网络请求
     *
     * @param clazz  需要解析的class
     * @param params 参数
     * @param url    地址
     * @param <T>
     */
    public static <T> void getRequestHttpByPost(Class<T> clazz, HashMap<String, String> params, String url) {
        mThreadPools.execute(() -> {
            FormBody.Builder builder = new FormBody.Builder();
            Request.Builder request = new Request.Builder().url(url);
            if (params != null && params.size() != 0) {
                Log.e(TAG, params.toString());
                Set<Map.Entry<String, String>> entries = params.entrySet();
                for (Map.Entry<String, String> entry : entries) {
                    builder.add(entry.getKey(), entry.getValue());
                }
                request.post(builder.build());
            }
            if (mOkHttpClient == null) {
                throw new NullPointerException("Not init mOkHttpClient");
            }
            Call newCall = mOkHttpClient.newCall(request.build());
            try {
                Response response = newCall.execute();
                if (response.code() == 200 && Objects.requireNonNull(response.body()).string() != null) {
                    T jsonResult = GsonUtils.mGson.fromJson(Objects.requireNonNull(response.body()).string(), clazz);
                    EventBus.getDefault().post(jsonResult);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * post网络请求
     *
     * @param clazz  需要解析的class
     * @param params 参数
     * @param url    地址
     * @param <T>
     */
    public static <T> void getRequestHttpByPostJson(Class<T> clazz, HashMap<String, Object> params, String url) {
        mThreadPools.execute(() -> {
            try {
                Request.Builder request = new Request.Builder().url(url);
                if (params != null && params.size() != 0) {
                    Log.e(TAG, params.toString());
                    JSONObject jsonObject = new JSONObject();
                    Set<Map.Entry<String, Object>> entries = params.entrySet();
                    for (Map.Entry<String, Object> entry : entries) {
                        jsonObject.put(entry.getKey(), entry.getValue());
                    }
                    RequestBody requestBody = FormBody.create(MediaType.parse("application/json; charset=utf-8"), jsonObject.toString());
                    request.post(requestBody);
                }
                if (mOkHttpClient == null) {
                    throw new NullPointerException("Not init mOkHttpClient");
                }
                Call newCall = mOkHttpClient.newCall(request.build());
                Response response = newCall.execute();
                if (response.code() == 200 && Objects.requireNonNull(response.body()).string() != null) {
                    T jsonResult = GsonUtils.mGson.fromJson(Objects.requireNonNull(response.body()).string(), clazz);
                    EventBus.getDefault().post(jsonResult);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * @param context 设置OKHttp的Cookies
     */
    public static void setOkHttp(Context context) {
        mOkHttpClient = new OkHttpClient.Builder()
                .cookieJar(new CookiesManager(context))
                .connectTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .readTimeout(20, TimeUnit.SECONDS)
                .build();
        okHttpStart();
    }

    /**
     * 启动联网请求
     */
    private static void okHttpStart() {
        mThreadPools.execute(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    synchronized (mArrayBlockingQueue) {
                        while (mArrayBlockingQueue.size() == 0) {
                            try {
                                mArrayBlockingQueue.wait();
                            } catch (InterruptedException e) {
                                mArrayBlockingQueue.notify();
                            }
                        }
                        OkHttpParam poll = mArrayBlockingQueue.poll();
                        if (poll.isJson) {
                            getRequestHttpByPostJson(poll.clazz, poll.params, poll.url);
                        } else {
                            HashMap<String, Object> params = poll.params;
                            HashMap<String, String> hashMap = new HashMap<>();
                            Set<String> strings = params.keySet();
                            for (String string : strings) {
                                hashMap.put(string, (String) params.get(string));
                            }
                            getRequestHttpByPost(poll.clazz, hashMap, poll.url);
                        }
                        mArrayBlockingQueue.notify();
                    }
                }
            }
        });
        mThreadPools.execute(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    synchronized (mArrayBlockingQueue) {
                        while (mArrayBlockingQueue.size() == mSize) {
                            try {
                                mArrayBlockingQueue.wait();
                            } catch (InterruptedException e) {
                                mArrayBlockingQueue.notify();
                            }
                        }
                        if (mOkHttpUtilsInnerClass != null) {
                            mArrayBlockingQueue.offer(new OkHttpParam(mOkHttpUtilsInnerClass));
                            mOkHttpUtilsInnerClass = null;
                            mArrayBlockingQueue.notify();
                        } else {
                            try {
                                mArrayBlockingQueue.wait();
                            } catch (InterruptedException e) {
                                mArrayBlockingQueue.notify();
                            }
                        }
                    }
                }
            }
        });
    }

    /**
     * 添加网络请求
     *
     * @param okHttpUtilsInnerClass
     */
    public static void setOkHttpUtilsInnerClass(OkHttpParam okHttpUtilsInnerClass) {
        mOkHttpUtilsInnerClass = okHttpUtilsInnerClass;
    }

    /**
     * 为HttpGet 的 url 方便的添加多个name value 参数。
     *
     * @param url
     * @param params
     * @return
     */
    public static String attachHttpGetParams(String url, LinkedHashMap<String, String> params) {
        Iterator<String> keys = params.keySet().iterator();
        Iterator<String> values = params.values().iterator();
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("?");
        for (int i = 0; i < params.size(); i++) {
            String value = null;
            try {
                value = URLEncoder.encode(values.next(), "utf-8");
            } catch (Exception e) {
                e.printStackTrace();
            }
            stringBuffer.append(keys.next() + "=" + value);
            if (i != params.size() - 1) {
                stringBuffer.append("&");
            }
            Log.v(TAG, stringBuffer.toString());
        }
        return url + stringBuffer.toString();
    }
}
